package com.warmheart.core.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.annotation.Immutable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.warmheart.base.executor.MdcThreadPoolTaskExecutor;
import com.warmheart.core.ex.ServerException;
import com.warmheart.core.ex.base.CoreWhException;
import com.warmheart.core.util.ApplicationContextUtil;

/**
 * 
 * @ClassName: PoolTaskOper
 * @Description: 线程池任务操作类
 * @author ZhangJianyang
 * @date 2025-06-16 09:37:02
 *
 */
@Immutable
class PoolOper {

    private static final Logger logger = LoggerFactory.getLogger(PoolOper.class);

    /**
     * 包含返回值的执行逻辑以及消费逻辑
     */
    private List<PoolResult<?>> poolResultList;

    /**
     * 不包含返回值的执行逻辑
     */
    private Map<String, WhRunnable> runnableMap;

    /**
     * 线程池
     */
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    protected PoolOper() {
    }

    public PoolOper(List<PoolResult<?>> poolResultList, Map<String, WhRunnable> runnableMap,
            ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        this.poolResultList = poolResultList;
        this.runnableMap = runnableMap;
        this.threadPoolTaskExecutor = threadPoolTaskExecutor;
    }

    static PoolOper.Builder custom(Map<String, WhRunnable> runnableMap,
            ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        return new Builder(null, runnableMap, threadPoolTaskExecutor);
    }

    static PoolOper.Builder custom(List<PoolResult<?>> poolResultList, ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        return new Builder(poolResultList, null, threadPoolTaskExecutor);
    }

    static class Builder {

        /**
         * 包含返回值的执行逻辑以及消费逻辑
         */
        private List<PoolResult<?>> poolResultList;

        /**
         * 不包含返回值的执行逻辑
         */
        private Map<String, WhRunnable> runnableMap;

        /**
         * 线程池
         */
        private ThreadPoolTaskExecutor threadPoolTaskExecutor;

        private Builder(List<PoolResult<?>> poolResultList, Map<String, WhRunnable> runnableMap,
                ThreadPoolTaskExecutor threadPoolTaskExecutor) {
            super();
            this.poolResultList = poolResultList;
            this.runnableMap = runnableMap;
            if (threadPoolTaskExecutor == null) {
                this.threadPoolTaskExecutor = ApplicationContextUtil.getServiceBean("mdcThreadPoolTaskExecutor",
                        MdcThreadPoolTaskExecutor.class);
            } else {
                this.threadPoolTaskExecutor = threadPoolTaskExecutor;
            }
        }

        public PoolOper build() {
            return new PoolOper(this.poolResultList, this.runnableMap, this.threadPoolTaskExecutor);
        }
    }

    /**
     * 
     * @Title: execute
     * @Description: 线程池执行逻辑
     * @author ZhangJianyang
     * @return
     * @throws ServerException
     */
    void run() throws ServerException {
        if (this.runnableMap != null && !runnableMap.isEmpty()) {
            for (String runnableKey : this.runnableMap.keySet()) {
                CompletableFuture.runAsync(this.runnableMap.get(runnableKey), this.threadPoolTaskExecutor)
                        .whenComplete((res, e) -> {
                            if (e != null) {
                                Throwable throwable = e.getCause();
                                if (throwable instanceof CoreWhException) {
                                    CoreWhException coreWhException = (CoreWhException) throwable;
                                    logger.error(coreWhException.getMessage(), coreWhException);
                                    return;
                                }
                                if (StringUtils.isNotBlank(this.runnableMap.get(runnableKey).getRemarks())) {
                                    logger.error(this.runnableMap.get(runnableKey).getRemarks() + "失败", throwable);
                                    return;
                                }
                                logger.error("子线程执行任务失败", throwable);
                            }
                        });
            }
        }
    }

    /**
     * 
     * @Title: waitFor
     * @Description: 线程池执行逻辑并等待执行完成
     * @author ZhangJianyang
     * @throws ServerException
     */
    void waitFor() throws ServerException {
        List<CompletableFuture<?>> cfList = new ArrayList<CompletableFuture<?>>();
        if (this.poolResultList != null && this.poolResultList.size() > 0) {
            for (PoolResult<?> currPoolResult : this.poolResultList) {
                if (currPoolResult.getWhScfInfo() != null) {
                    handler(currPoolResult.getWhScfInfo());
                    cfList.add(currPoolResult.getWhScfInfo().getFuture());
                }
            }
        }
        if (this.runnableMap != null && !runnableMap.isEmpty()) {
            for (String runnableKey : this.runnableMap.keySet()) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(this.runnableMap.get(runnableKey),
                        this.threadPoolTaskExecutor).exceptionally((e) -> {
                    Throwable throwable = e.getCause();
                    if (throwable instanceof CoreWhException) {
                        CoreWhException coreWhException = (CoreWhException) throwable;
                        logger.error(coreWhException.getMessage(), coreWhException);
                        throw coreWhException;
                    }
                    if (StringUtils.isNotBlank(this.runnableMap.get(runnableKey).getRemarks())) {
                        logger.error(this.runnableMap.get(runnableKey).getRemarks(), throwable);
                        throw new ServerException(this.runnableMap.get(runnableKey).getRemarks() + "失败", throwable);
                    } else {
                        logger.error("子线程执行任务失败", throwable);
                        throw new ServerException(throwable);
                    }
                });
                cfList.add(future);
            }
        }
        if (cfList.size() > 0) {
            try {
                // 等待请求完成
                CompletableFuture.allOf(cfList.stream().toArray(CompletableFuture[]::new)).exceptionally((e) -> {
                    Throwable throwable = e.getCause();
                    if (throwable instanceof CoreWhException) {
                        CoreWhException coreWhException = (CoreWhException) throwable;
                        throw coreWhException;
                    }
                    throw new ServerException("子线程执行任务失败", throwable);
                }).join();
            } catch (Exception e) {
                Throwable throwable = e.getCause();
                if (throwable instanceof CoreWhException) {
                    CoreWhException coreWhException = (CoreWhException) throwable;
                    throw coreWhException;
                }
                throw new ServerException("子线程执行任务失败", throwable);
            }
            if (this.poolResultList != null && this.poolResultList.size() > 0) {
                for (PoolResult<?> currPoolResult : this.poolResultList) {
                    if (currPoolResult.getWhScfInfo() != null) {
                        currPoolResult.handlerResult();
                    }
                }
            }
        }
    }

    private <T> void handler(WhScfInfo<T> whScfInfo) {
        whScfInfo.setFuture(CompletableFuture.supplyAsync(whScfInfo.supplier(), this.threadPoolTaskExecutor)
                .exceptionally((e) -> {
                    Throwable throwable = e.getCause();
                    if (throwable instanceof CoreWhException) {
                        CoreWhException coreWhException = (CoreWhException) throwable;
                        logger.error(coreWhException.getMessage(), coreWhException);
                        throw coreWhException;
                    }
                    if (StringUtils.isNotBlank(whScfInfo.supplier().getRemarks())) {
                        logger.error(whScfInfo.supplier().getRemarks(), throwable);
                        throw new ServerException(whScfInfo.supplier().getRemarks() + "失败", throwable);
                    } else {
                        logger.error("子线程执行任务失败", throwable);
                        throw new ServerException(throwable);
                    }
                }));
    }
}